package com.scriptlib;

import android.graphics.Point;

import java.util.Arrays;

public class AnchorGraphicHelper {
    private static final int _LEFT = 0;
    private static final int _CENTER = 1;
    private static final int _RIGHT = 2;
    private final ScreenHelper screenHelper;
    private byte[] screenData;
    private int width;
    private int height;
    private int rowStride;
    private boolean isInit = false;
    private final int left;
    private final int top;
    private final int right;
    private final int bottom;
    private final int center;
    private final int devWidth;
    private final int devHeight;
    private final double multiple;

    public AnchorGraphicHelper(Object obj, int[] describe) {
        this.screenHelper = new ScreenHelper(obj);
        this.devWidth = describe[0];
        this.devHeight = describe[1];
        this.left = describe[2];
        this.top = describe[3];
        this.right = describe[4];
        this.bottom = describe[5];
        this.center = Round((right - left + 1.0) / 2 - 1);
        this.multiple = (bottom - top + 1.0) / devHeight;
    }

    public AnchorGraphicHelper(Object obj, int devWidth, int devHeight, int left, int top, int right, int bottom) {
        this.screenHelper = new ScreenHelper(obj);
        this.devWidth = devWidth;
        this.devHeight = devHeight;
        this.left = left;
        this.top = top;
        this.right = right;
        this.bottom = bottom;
        this.center = Round((this.right - this.left + 1.0) / 2);
        this.multiple = (this.bottom - this.top + 1.0) / devHeight;

    }

    static public String Version() {
        return "9.19.0";
    }

    public boolean KeepScreen() {
        if (screenHelper.GetLastFrame()) {
            if (!isInit) {
                isInit = true;
                width = screenHelper.GetWidth();
                height = screenHelper.GetHeight();
                rowStride = width * 4;
            }
            screenData = screenHelper.GetScreenData();
            return true;
        } else {
            return false;
        }
    }

    private int Round(double num) {//四舍六入五成双
        int local = (int) ((num - (int) num) * 100);
        if (local / 10 >= 6)
            return (int) num + 1;
        if (local / 10 <= 4)
            return (int) num;
        if (local % 10 == 0) {
            if ((int) num % 2 == 0) {
                return (int) num;
            }
        }
        return (int) num + 1;
    }

    public byte[] GetScreenData() {
        return screenData;
    }

    public Point GetPoint(int x, int y, int mode) {
        Point result = new Point();
        if (mode == _LEFT) {
            result.x = Round(x * multiple) + left;
        } else if (mode == _CENTER) {
            result.x = Round(center - (devWidth / 2.0 - x - 1) * multiple);
        } else if (mode == _RIGHT) {
            result.x = Round(right - (devWidth - x - 1) * multiple);
        }
        result.y = Round(y * multiple) + top;
        return result;
    }

    public String GetPixelStr(int x, int y, int mode) {
        int[] result = GetPixel(x, y, mode);
        int color = (result[0] & 0xff) << 16 | (result[1] & 0xff) << 8 | (result[2] & 0xff);
        return String.format("0x%06x", color);
    }

    public int GetPixelInt(int x, int y, int mode) {
        int[] result = GetPixel(x, y, mode);
        return (result[0] & 0xff) << 16 | (result[1] & 0xff) << 8 | (result[2] & 0xff);
    }

    public int[] GetPixel(int x, int y, int mode) {
        Point point = GetPoint(x, y, mode);
        if (point.x >= 0 && point.x < width && point.y >= 0 && point.y < height) {
            int location = point.x * 4 + point.y * rowStride;
            int[] result = new int[3];
            result[0] = screenData[location] & 0xff;
            result[1] = screenData[location + 1] & 0xff;
            result[2] = screenData[location + 2] & 0xff;
            return result;
        } else {
            return new int[]{0, 0, 0};
        }
    }

    public boolean CompareColor(int[] compareColor, int sim, int offset) {
        offset = Math.min(offset, 1);
        int x;
        int y;
        int offsetX = 0;
        int offsetY = 0;
        int size = (offset * 2 + 1) * (offset * 2 + 1);

        int similarity = Round(255 - 255 * (sim / 100.0));
        int similarity_R = similarity + compareColor[5];
        int similarity_G = similarity + compareColor[6];
        int similarity_B = similarity + compareColor[7];

        for (int i = 0; i < size; i++) {
            x = compareColor[0] + offsetX;
            y = compareColor[1] + offsetY;
            if (x >= 0 && x < width && y >= 0 && y < height) {
                int location = x * 4 + y * rowStride;
                if (Math.abs((screenData[location] & 0xff) - compareColor[2]) <= similarity_R) {
                    if (Math.abs((screenData[location + 1] & 0xff) - compareColor[3]) <= similarity_G) {
                        if (Math.abs((screenData[location + 2] & 0xff) - compareColor[4]) <= similarity_B) {
                            return true;
                        }
                    }
                }
            }

            for (int j = 1; j <= offset; j++) {
                if (offsetX == 0 && offsetY == (-j)) {
                    offsetX += 1;
                } else if (offsetX == j && offsetY == (-j)) {
                    offsetY += 1;
                } else if (offsetX == j && offsetY == j) {
                    offsetX -= 1;
                } else if (offsetX == (-j) && offsetY == j) {
                    offsetY -= 1;
                } else if (offsetX == (-j) && offsetY == (-j - 1)) {
                    offsetX += 1;
                }
            }
        }
        return false;
    }

    public boolean CompareColor(int devWidth, int devHeight, int[] compareColor, int sim, int offset) {
        double multiple = (bottom - top + 1.0) / devHeight;
        int[] color = new int[8];
        if (compareColor[0] == _LEFT) {
            color[0] = Round(compareColor[1] * multiple) + left;
        } else if (compareColor[0] == _CENTER) {
            color[0] = Round(center - (devWidth / 2.0 - compareColor[1] - 1) * multiple);
        } else if (compareColor[0] == _RIGHT) {
            color[0] = Round(right - (devWidth - compareColor[1] - 1) * multiple);
        }
        color[1] = Round(compareColor[2] * multiple) + top;
        color[2] = (compareColor[3] & 0xff0000) >> 16;
        color[3] = (compareColor[3] & 0xff00) >> 8;
        color[4] = compareColor[3] & 0xff;
        color[5] = color[6] = color[7] = 0;
        if (compareColor.length == 5) {
            color[5] = (compareColor[4] & 0xff0000) >> 16;
            color[6] = (compareColor[4] & 0xff00) >> 8;
            color[7] = compareColor[4] & 0xff;
        }

        offset = Math.min(offset, 1);
        int x;
        int y;
        int offsetX = 0;
        int offsetY = 0;
        int size = (offset * 2 + 1) * (offset * 2 + 1);

        int similarity = Round(255 - 255 * (sim / 100.0));
        int similarity_R = similarity + color[5];
        int similarity_G = similarity + color[6];
        int similarity_B = similarity + color[7];

        for (int i = 0; i < size; i++) {
            x = color[0] + offsetX;
            y = color[1] + offsetY;
            if (x >= 0 && x < width && y >= 0 && y < height) {
                int location = x * 4 + y * rowStride;
                if (Math.abs((screenData[location] & 0xff) - color[2]) <= similarity_R) {
                    if (Math.abs((screenData[location + 1] & 0xff) - color[3]) <= similarity_G) {
                        if (Math.abs((screenData[location + 2] & 0xff) - color[4]) <= similarity_B) {
                            return true;
                        }
                    }
                }
            }

            for (int j = 1; j <= offset; j++) {
                if (offsetX == 0 && offsetY == (-j)) {
                    offsetX += 1;
                } else if (offsetX == j && offsetY == (-j)) {
                    offsetY += 1;
                } else if (offsetX == j && offsetY == j) {
                    offsetX -= 1;
                } else if (offsetX == (-j) && offsetY == j) {
                    offsetY -= 1;
                } else if (offsetX == (-j) && offsetY == (-j - 1)) {
                    offsetX += 1;
                }
            }
        }
        return false;
    }

    // <editor-fold desc="CompareColorEx">
    private boolean CompareColor2Ex(int[] compareColor, int similarity, int offset) {
        offset = Math.min(offset, 1);
        int x;
        int y;
        int offsetX = 0;
        int offsetY = 0;
        int size = (offset * 2 + 1) * (offset * 2 + 1);
        int similarity_R = similarity + compareColor[5];
        int similarity_G = similarity + compareColor[6];
        int similarity_B = similarity + compareColor[7];

        for (int i = 0; i < size; i++) {
            x = compareColor[0] + offsetX;
            y = compareColor[1] + offsetY;
            if (x >= 0 && x < width && y >= 0 && y < height) {
                int location = x * 4 + y * rowStride;
                if (Math.abs((screenData[location] & 0xff) - compareColor[2]) <= similarity_R) {
                    if (Math.abs((screenData[location + 1] & 0xff) - compareColor[3]) <= similarity_G) {
                        if (Math.abs((screenData[location + 2] & 0xff) - compareColor[4]) <= similarity_B) {
                            return true;
                        }
                    }
                }
            }

            for (int j = 1; j <= offset; j++) {
                if (offsetX == 0 && offsetY == (-j)) {
                    offsetX += 1;
                } else if (offsetX == j && offsetY == (-j)) {
                    offsetY += 1;
                } else if (offsetX == j && offsetY == j) {
                    offsetX -= 1;
                } else if (offsetX == (-j) && offsetY == j) {
                    offsetY -= 1;
                } else if (offsetX == (-j) && offsetY == (-j - 1)) {
                    offsetX += 1;
                }
            }
        }
        return false;
    }

    public boolean CompareColorEx(int[][] compareColors, int sim, int offset) {
        int similarity = Round(255 - 255 * (sim / 100.0));
        for (int[] color : compareColors) {
            if (!CompareColor2Ex(color, similarity, offset)) {
                return false;
            }
        }
        return true;
    }

    public boolean CompareColorEx(int devWidth, int devHeight, int[][] compareColors, int sim, int offset) {
        double multiple = (bottom - top + 1.0) / devHeight;
        int[][] colors = new int[compareColors.length][8];
        for (int i = 0; i < compareColors.length; i++) {
            if (compareColors[i][0] == _LEFT) {
                colors[i][0] = Round(compareColors[i][1] * multiple) + left;
            } else if (compareColors[i][0] == _CENTER) {
                colors[i][0] = Round(center - (devWidth / 2.0 - compareColors[i][1] - 1) * multiple);
            } else if (compareColors[i][0] == _RIGHT) {
                colors[i][0] = Round(right - (devWidth - compareColors[i][1] - 1) * multiple);
            }
            colors[i][1] = Round(compareColors[i][2] * multiple) + top;
            colors[i][2] = (compareColors[i][3] & 0xff0000) >> 16;
            colors[i][3] = (compareColors[i][3] & 0xff00) >> 8;
            colors[i][4] = compareColors[i][3] & 0xff;
            colors[i][5] = colors[i][6] = colors[i][7] = 0;
            if (compareColors[i].length == 5) {
                colors[i][5] = (compareColors[i][4] & 0xff0000) >> 16;
                colors[i][6] = (compareColors[i][4] & 0xff00) >> 8;
                colors[i][7] = compareColors[i][4] & 0xff;
            }
        }
        return CompareColorEx(colors, sim, offset);
    }

    public int[][] GetCmpColorArray(int devWidth, int devHeight, int[][] compareColors) {
        double multiple = (bottom - top + 1.0) / devHeight;
        int[][] colors = new int[compareColors.length][8];
        for (int i = 0; i < compareColors.length; i++) {
            if (compareColors[i][0] == _LEFT) {
                colors[i][0] = Round(compareColors[i][1] * multiple) + left;
            } else if (compareColors[i][0] == _CENTER) {
                colors[i][0] = Round(center - (devWidth / 2.0 - compareColors[i][1] - 1) * multiple);
            } else if (compareColors[i][0] == _RIGHT) {
                colors[i][0] = Round(right - (devWidth - compareColors[i][1] - 1) * multiple);
            }
            colors[i][1] = Round(compareColors[i][2] * multiple) + top;
            colors[i][2] = (compareColors[i][3] & 0xff0000) >> 16;
            colors[i][3] = (compareColors[i][3] & 0xff00) >> 8;
            colors[i][4] = compareColors[i][3] & 0xff;
            colors[i][5] = colors[i][6] = colors[i][7] = 0;
            if (compareColors[i].length == 5) {
                colors[i][5] = (compareColors[i][4] & 0xff0000) >> 16;
                colors[i][6] = (compareColors[i][4] & 0xff00) >> 8;
                colors[i][7] = compareColors[i][4] & 0xff;
            }
        }
        return colors;
    }

// </editor-fold>
    // <editor-fold desc="FindMultiColor">

    private boolean CompareColorEx2FC(int[][] compareColors, int similarity, int x, int y, int offset) {
        for (int[] _compareColor : compareColors) {
            int[] compareColor = Arrays.copyOf(_compareColor, _compareColor.length);
            compareColor[0] = compareColor[0] + x;
            compareColor[1] = compareColor[1] + y;
            if (!CompareColor2Ex(compareColor, similarity, offset)) {
                return false;
            }
        }
        return true;
    }

    public Point FindMultiColor(int startX, int startY, int endX, int endY, int[][] describeColors, int sim, int offset) {
        int[][] compareColors = new int[describeColors.length - 1][8];
        System.arraycopy(describeColors, 1, compareColors, 0, compareColors.length);
        if (startX < endX && endX < width && startY < endY && endY < height) {
            int similarity = Round(255 - 255 * (sim / 100.0));
            int similarity_R = similarity + describeColors[0][5];
            int similarity_G = similarity + describeColors[0][6];
            int similarity_B = similarity + describeColors[0][7];

            for (int i = startY; i <= endY; i++) {
                int location = startX * 4 + i * rowStride;
                for (int j = startX; j <= endX; j++) {
                    if (Math.abs((screenData[location] & 0xff) - describeColors[0][2]) <= similarity_R) {
                        if (Math.abs((screenData[location + 1] & 0xff) - describeColors[0][3]) <= similarity_G) {
                            if (Math.abs((screenData[location + 2] & 0xff) - describeColors[0][4]) <= similarity_B) {
                                if (CompareColorEx2FC(compareColors, similarity, j, i, offset)) {
                                    return new Point(j, i);
                                }
                            }
                        }
                    }
                    location += 4;
                }
            }
        }
        return new Point(-1, -1);
    }

    public Point FindMultiColor(int startX, int startY, int endX, int endY, int devWidth, int devHeight, int[][] describeColors, int sim, int offset) {
        int[][] colors = new int[describeColors.length][8];
        double multiple = (bottom - top + 1.0) / devHeight;
        if (describeColors[0][0] == _LEFT) {
            colors[0][0] = Round(describeColors[0][1] * multiple) + left;
        } else if (describeColors[0][0] == _CENTER) {
            colors[0][0] = Round(center - (devWidth / 2.0 - describeColors[0][1] - 1) * multiple);
        } else if (describeColors[0][0] == _RIGHT) {
            colors[0][0] = Round(right - (devWidth - describeColors[0][1] - 1) * multiple);
        }
        colors[0][1] = Round(describeColors[0][2] * multiple);
        colors[0][2] = (describeColors[0][3] & 0xff0000) >> 16;
        colors[0][3] = (describeColors[0][3] & 0xff00) >> 8;
        colors[0][4] = describeColors[0][3] & 0xff;
        colors[0][5] = colors[0][6] = colors[0][7] = 0;
        if (describeColors[0].length == 5) {
            colors[0][5] = (describeColors[0][4] & 0xff0000) >> 16;
            colors[0][6] = (describeColors[0][4] & 0xff00) >> 8;
            colors[0][7] = describeColors[0][4] & 0xff;
        }
        for (int i = 1; i < describeColors.length; i++) {
            if (describeColors[i][0] == _LEFT) {
                colors[i][0] = Round(describeColors[0][1] * multiple) + left - colors[0][0];
            } else if (describeColors[i][0] == _CENTER) {
                colors[i][0] = Round(center - (devWidth / 2.0 - describeColors[i][1] - 1) * multiple) - colors[0][0];
            } else if (describeColors[i][0] == _RIGHT) {
                colors[i][0] = Round(right - (devWidth - describeColors[i][1] - 1) * multiple) - colors[0][0];
            }
            colors[i][1] = Round(describeColors[i][2] * multiple) + top - colors[0][1];
            colors[i][2] = (describeColors[i][3] & 0xff0000) >> 16;
            colors[i][3] = (describeColors[i][3] & 0xff00) >> 8;
            colors[i][4] = describeColors[i][3] & 0xff;
            colors[i][5] = colors[i][6] = colors[i][7] = 0;
            if (describeColors[i].length == 5) {
                colors[i][5] = (describeColors[i][4] & 0xff0000) >> 16;
                colors[i][6] = (describeColors[i][4] & 0xff00) >> 8;
                colors[i][7] = describeColors[i][4] & 0xff;
            }
        }
        return FindMultiColor(startX, startY, endX, endY, colors, sim, offset);
    }

    public int[][] GetFindColorArray(int devWidth, int devHeight, int[][] describeColors) {
        int[][] colors = new int[describeColors.length][8];
        double multiple = (bottom - top + 1.0) / devHeight;
        if (describeColors[0][0] == _LEFT) {
            colors[0][0] = Round(describeColors[0][1] * multiple) + left;
        } else if (describeColors[0][0] == _CENTER) {
            colors[0][0] = Round(center - (devWidth / 2.0 - describeColors[0][1] - 1) * multiple);
        } else if (describeColors[0][0] == _RIGHT) {
            colors[0][0] = Round(right - (devWidth - describeColors[0][1] - 1) * multiple);
        }
        colors[0][1] = Round(describeColors[0][2] * multiple);
        colors[0][2] = (describeColors[0][3] & 0xff0000) >> 16;
        colors[0][3] = (describeColors[0][3] & 0xff00) >> 8;
        colors[0][4] = describeColors[0][3] & 0xff;
        colors[0][5] = colors[0][6] = colors[0][7] = 0;
        if (describeColors[0].length == 5) {
            colors[0][5] = (describeColors[0][4] & 0xff0000) >> 16;
            colors[0][6] = (describeColors[0][4] & 0xff00) >> 8;
            colors[0][7] = describeColors[0][4] & 0xff;
        }
        for (int i = 1; i < describeColors.length; i++) {
            if (describeColors[i][0] == _LEFT) {
                colors[i][0] = Round(describeColors[i][1] * multiple) + left - colors[0][0];
            } else if (describeColors[i][0] == _CENTER) {
                colors[i][0] = Round(center - (devWidth / 2.0 - describeColors[i][1] - 1) * multiple) - colors[0][0];
            } else if (describeColors[i][0] == _RIGHT) {
                colors[i][0] = Round(right - (devWidth - describeColors[i][1] - 1) * multiple) - colors[0][0];
            }
            colors[i][1] = Round(describeColors[i][2] * multiple) + top - colors[0][1];
            colors[i][2] = (describeColors[i][3] & 0xff0000) >> 16;
            colors[i][3] = (describeColors[i][3] & 0xff00) >> 8;
            colors[i][4] = describeColors[i][3] & 0xff;
            colors[i][5] = colors[i][6] = colors[i][7] = 0;
            if (describeColors[i].length == 5) {
                colors[i][5] = (describeColors[i][4] & 0xff0000) >> 16;
                colors[i][6] = (describeColors[i][4] & 0xff00) >> 8;
                colors[i][7] = describeColors[i][4] & 0xff;
            }
        }
        return colors;
    }


// </editor-fold>

}
